
package edu.cmu.vlis.datamining.TopologicalFeatures;
import java.util.*;
import java.io.*;

public class SimpleCascadeEnumeration {

	// woo double hashing
	static HashMap<Integer,HashMap<Cascade,Integer>> cascadeTypes = new HashMap<Integer,HashMap<Cascade,Integer>>();
	static HashMap<Cascade,Integer> cascadeToId = new  HashMap<Cascade,Integer>();
	static HashMap<Integer,Cascade> idToCascade = new HashMap<Integer,Cascade>();
	static int cID = 0;
	/*    static String inFile;
    static String idout;
    static String cascadeout;*/

	/*public static void main(String[] args) {
	if (args.length!=3) {
	    System.out.println("3 arguments needed-- infile idout cascadeout");
	    System.exit(1);
	}
	String inFile = args[0];
	String idout = args[1];
	String cascadeout = args[2];
	enumerateCascades(inFile, cascadeout);
	printIdsToCascades(idout);

    }*/


	static CascadeReturn runClass(CascadeReturn cr) {//String inStr,String idout,String cascadeout) {
		String cascadeOut = enumerateCascades(cr.getNewCascade());
		System.out.println("her!!!");
		String idOut =printIdsToCascades();
		System.out.println("here!");
		cr.setId(cascadeOut);
		cr.setDistinctCascade(idOut);
		return cr;
	}

	static String printIdsToCascades() {
		String stringOut="";
		//try {
		//   FileWriter fw = new FileWriter(outfile);
		for (int i = 0; i < cID; i++) {
			Cascade curr = idToCascade.get(i);
			curr.remapToGeneric();
			stringOut = stringOut + i+": "+curr.getEdges()+"\n";
		}
		// fw.close();
		//}
		//catch(IOException e ) {
		//    e.printStackTrace();
		//	}
		return stringOut;
	}



	static String enumerateCascades(String inStr) {
		try{
			CascadeIterator ci = new CascadeIterator(inStr);
			String cascadeout="";
			//System.out.println(inStr);

			long starttime = System.currentTimeMillis();

			//try {
			//FileWriter fw = new FileWriter(outFile);	    
			int k =0;
			while (ci.hasNext()) {
				k++;
				if (k % 10000==0)
					System.out.println(k);
				int nextSize = ci.getNextSize();
				System.out.println("nextSize");
				if(nextSize>0) {
					if (nextSize < 100) {
						Cascade c = ci.next();
						if(c==null) {
							System.out.println("breaking as null");
							break;
						}
						int type = incrementHashtable(c);
						cascadeout = cascadeout + type+"\n";
					}
					else ci.advanceWithoutFetch();
				}
			}
			//	    fw.close();
			//	}
			//	catch(IOException e) {
			//e.printStackTrace();
			//}
			/*
	getChainSizes();
	getStarSizes();
	for (int i = 0; i < 100; i++) {
	    int num =cascadesOfSizeN(i);
	    int types = cascadeTypesOfSizeN(i);
	    System.out.println(i+"\t"+types+"\t"+num);
	}
			 */  
			//printHashtable(100);
			long endtime = System.currentTimeMillis();
			//System.out.println((double)(endtime-starttime)/(double)1000);
			return cascadeout;
		}catch(NullPointerException e) {

			System.out.println(e.toString());
			return "";
		}

	}



	static void getStarSizes() {
		int maxsize=20;
		for (int i =2; i < maxsize; i++) {
			String cascadeString = "";
			for (int j = 0; j < i-1; j++) {
				cascadeString = cascadeString +j+" "+(i-1)+" ";
			}
			Cascade c = new Cascade(cascadeString);
			int num = 0;
			if (cascadeTypes.containsKey(i)) {
				HashMap<Cascade,Integer> ntable = cascadeTypes.get(i);
				Iterator<Cascade> candit = ntable.keySet().iterator();
				while (candit.hasNext()) {
					Cascade cand = candit.next();
					if (Cascade.isomorphic(cand,c)) {
						num = ntable.get(cand);
						break;
					}
				}


			}
			//System.out.println(i+"\t"+num);
		}




	}

	static void getChainSizes() {
		int maxsize=20;
		for (int i =2; i < maxsize; i++) {
			String cascadeString = "";
			for (int j = 0; j < i-1; j++) {
				cascadeString = cascadeString +j+" "+(j+1)+" ";
			}
			System.out.println(cascadeString);
			Cascade c = new Cascade(cascadeString);
			int num = 0;
			if (cascadeTypes.containsKey(i)) {
				HashMap<Cascade,Integer> ntable = cascadeTypes.get(i);
				Iterator<Cascade> candit = ntable.keySet().iterator();
				while (candit.hasNext()) {
					Cascade cand = candit.next();
					if (Cascade.isomorphic(cand,c)) {
						num = ntable.get(cand);
						break;
					}
				}


			}
			//System.out.println(i+"\t"+num);
		}


	}

	static int cascadeTypesOfSizeN(int n) {
		if (cascadeTypes.containsKey(n))
			return cascadeTypes.get(n).size();
		else return 0;
	}

	static int cascadesOfSizeN(int n) {
		int count = 0;
		if (cascadeTypes.containsKey(n)) {
			Iterator<Integer> vals = cascadeTypes.get(n).values().iterator();
			while (vals.hasNext()) {
				count += vals.next();
			}

		}
		return count;

	}

	static int incrementHashtable(Cascade c) {
		//returns the id of the cascade identified (id is not at all pre-planned, but specific to the dataset)

		int myid=-1;
		try{
			System.out.println("ccc" + c);
			int n = c.size();
			System.out.println("ccc" + c.size());
			if (cascadeTypes.containsKey(n)) {
				HashMap<Cascade,Integer> ntable = cascadeTypes.get(n);
				Iterator<Cascade> candit = ntable.keySet().iterator();
				boolean found = false;
				while (candit.hasNext()) {
					Cascade cand = candit.next();
					if (Cascade.isomorphic(cand,c)) {
						int currval = ntable.get(cand);
						ntable.put(cand,++currval);
						found = true;
						myid = cascadeToId.get(cand);
						break;
					}
				}
				if (!found) {
					ntable.put(c,1);
					myid = cID++;
					cascadeToId.put(c,myid);
					idToCascade.put(myid,c);
				}
			}
			else {
				HashMap<Cascade,Integer> ntable = new HashMap<Cascade,Integer>();
				ntable.put(c,1);
				myid = cID++;
				cascadeToId.put(c,myid);
				idToCascade.put(myid,c);
				cascadeTypes.put(n,ntable);
			}
		}catch (Exception e) {
			System.out.println(e.toString());
		}
		return myid;
	}


	static void printHashtable(int maxn) {
		for (int n = 0; n < maxn; n++) {
			if (cascadeTypes.containsKey(n)) {
				System.out.println("--------- CASCADES OF SIZE "+n+" ---------");
				HashMap<Cascade,Integer> ntable = cascadeTypes.get(n);
				Iterator<Cascade> candit = ntable.keySet().iterator();
				while (candit.hasNext()) {
					Cascade cand = candit.next();
					int count = ntable.get(cand);
					cand.remapToGeneric();
					//System.out.print(count+" of ");
					cand.printEdgesParseFriendly();
				}

			}

		}

	}




}